#include "_my_printf.h"

int (*_my_fputc)(int ch);	
void printf_putc_callback_regist(int (*putc)(int ch))
{
	_my_fputc = putc;
}

/***********************************************************************
static void  _trace(const uint8_t *pstr)
{
	if(NULL == pstr)
		return;

	while(*pstr) {
		_my_fputc(*pstr);
		pstr++;
	}
}

static void byte2asc( uint8_t  *pStr, uint8_t bByte )
{
	const uint8_t Byte2Hex[] = "0123456789ABCDEF";

	*(pStr++) = Byte2Hex[ bByte >> 4  ];
	*(pStr++) = Byte2Hex[ bByte & 0xF ];
}

static void _hexstrTrace(uint8_t *pstr, uint8_t *pnum, uint16_t size)
{
	uint8_t  ch;
	uint8_t  buf[2] = {0, 0};

	_trace(pstr);

	while(size) {
		ch = *pnum++;
		byte2asc(buf, ch);
		_my_fputc(buf[0]);
		_my_fputc(buf[1]);
		size--;
	}
	_my_fputc(0x0D);
	_my_fputc(0x0A);
}
/*******************************************************************************
* Function:
*   print infomation through debug USART port.
*
*   support format:
*       %d,%i,%u    inter num
*       %x          display inter num in hex format
*       %c,%s       char & string
*       %%          '%'
*       %ld,%li,%lu,%lx = %d...
*       %md(eg:%4d),%mi,%mu,%mx,%ms : default right align
*
*   not support:
*       float num ralation: %f,...
*       %-md(eg:%-4d)...    : left align
* input:
* return:
*******************************************************************************
void _my_printf(const int8_t *str, ...)
{
	uint8_t *parg = 0;
	uint8_t  c;
	uint8_t  f;      // format
	// bit0:    padding  with '0'
	// bit1:    Long int
	// bit2:    minus
	// bit3:    signed int
	uint8_t  r;      // decimal or hex
	uint32_t val;
	uint8_t  s[16];
	uint32_t i;
	uint32_t w;      // width

	w = 0;
	f = 0;
	r = 0;

	parg = (uint8_t *)&str;
	parg += sizeof(str);

	while(1) {
		c = *str++;
		if (c == 0)
			break;

		if (c != '%') {
			_my_fputc(c);
			continue;
		}

		c = *str++;
		if (c == '%') {
			_my_fputc(c);
			continue;
		}

		if (c == 'c' || c == 'C') {
			_my_fputc(*((uint8_t *)parg));
			parg += sizeof(uint8_t *);
			continue;
		}

		w = 0;
		f = 0;
		if (c == '0') {             // '0' : padding
			f |= 0x1;
			c = *str++;
		}
		while (c >= '0' && c <= '9') {
			w = w * 10 + (c - '0');
			c = *str++;
		}
		if (c == 's' || c == 'S') {
			_trace( *(uint8_t **)parg);
			parg += sizeof(uint8_t *);
			continue;
		}

		if (c == 'l' || c == 'L') {
			f |= 0x2;
			c = *str++;
		}

		r = 0;
		if (c == 'd' || c == 'D' || c == 'i' || c == 'I') {
			r = 10;
			f |= 0x8;
		}
		else if (c == 'u' || c == 'U') {
			r = 10;
		}
		else if (c == 'X' || c == 'x') {
			r = 16;
		}

		if (r == 0) {
			break;
		}

		if (f & 0x2) {
			val = (uint32_t)(*((long *)parg));
			parg += sizeof(uint32_t);
		}
		else {
			val = (uint32_t)(*((uint32_t *)parg));
			parg += sizeof(uint32_t);
		}

		if (f & 0x8) {
			if (val & 0x80000000) {
				val = 0 - val;
				f |= 4;
			}
		}

		i = sizeof(s) - 1;
		s[i] = 0;
		do {
			c = (uint8_t)(val % r + '0');
			if (c > '9') {
				c += 7;
			}
			s[--i] = c;
			val /= r;
		}
		while (i && val);

		if (i && (f & 0x4)) {
			s[--i] = '-';
		}
		w = sizeof(s) - 1 - w;
		if(f & 0x1) {
			while (i && i > w) {
				s[--i] =  '0';
			}
		}
		else {
			while (i && i > w) {
				s[--i] =  ' ';
			}
		}
		_trace(&s[i]);
	}
	parg = 0;
}
***********************************************************************/
/***********************************************************************
void main(void)
{
	unsigned int b = 0xffffff9c;
	int a = b;

	_my_printf("%d, %x,%c\r\n",b,b,'f');
}
***********************************************************************/


static void _itoa(int value, char *string)
{
	char tmp[33];
	char *tp = tmp;
	char i;
	unsigned int v;
	char sign;
	char *sp;

	if (string == 0) {
		return;
	}

	sign = (value < 0);
	if (sign)
		v = -value;
	else
		v = (unsigned)value;
	while (v || tp == tmp) {
		i = v % 10;
		v = v / 10;
		if (i < 10)
			*tp++ = i + '0';
		else
			*tp++ = i + 'a' - 10;
	}
	sp = string;
	if (sign)
		*sp++ = '-';
	while (tp > tmp)
		*sp++ = *--tp;
	*sp = 0;
}


void printf_decimal(int value)
{
	char tmp[33];
	_itoa(value, tmp);
	printf_string(tmp);
}


void printf_byte_decimal(char a)
{		   // print a Byte in decimal format

	char v;
	char g, s, b;

	g = 0x0F & a;
	switch (g) {
	case 0x0a:
		v = 10;
		break;
	case 0x0b:
		v = 11;
		break;
	case 0x0c:
		v = 12;
		break;
	case 0x0d:
		v = 13;
		break;
	case 0x0e:
		v = 14;
		break;
	case 0x0f:
		v = 15;
		break;
	default:
		v = g;
		break;
	}
	v = ((0xF0 & a) >> 4) * 16 + v;

	b = v / 100;
	s = v % 100 / 10;
	g = v % 10;

#if 0
	if(b != 0)
	{
		uart_send_byte(b+0x30);
		uart_send_byte(s+0x30);
	}
	else if(s != 0)
	{
		uart_send_byte(s+0x30);
	}

	uart_send_byte(g+0x30);
#else
	//�̶�3������
	_my_fputc(b + 0x30);
	_my_fputc(s + 0x30);
	_my_fputc(g + 0x30);
#endif

}

void printf_float(float f)
{
	if ((f < 10) && (f > -10)) {
		uint8_t i;
		static uint8_t x[5];
		static uint32_t v;

		if (f < 0) {
			_my_fputc(0x2D);
			f = -f;
		}

		v = (uint32_t) (f * 1000);
		x[0] = v / 1000 + 0x30;
		v = v % 1000;
		x[1] = 0x2E;		//
		x[2] = v / 100 + 0x30;
		v = v % 100;
		x[3] = v / 10 + 0x30;
		x[4] = v % 10 + 0x30;

		for (i = 0; i < 5; i++) {
			_my_fputc(x[i]);
		}
	}
}


